package com.ruibang.glass.quality.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.Constants;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.domain.file.FileBusiness;
import com.ruibang.glass.quality.constant.QualityErrorCode;
import com.ruibang.glass.quality.domain.req.QualityStressReq;
import com.ruibang.glass.quality.domain.req.SemiCheckReportReq;
import com.ruibang.glass.quality.domain.resp.SemiCheckDetailData;
import com.ruibang.glass.quality.domain.resp.StressExcelDataResp;
import com.ruibang.glass.quality.entity.QualityStress;
import com.ruibang.glass.quality.entity.SpecsConfig;
import com.ruibang.glass.quality.feign.FileApi;
import com.ruibang.glass.quality.mapper.QualityStressMapper;
import com.ruibang.glass.quality.service.QualityStressService;
import com.ruibang.glass.quality.service.SpecsConfigService;
import com.ruibang.glass.quality.util.spc.SPCUtils;
import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import com.teaming.cloud.framework2.common.constant.CommonConstant;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import com.teaming.cloud.framework2.common.model.ResultBody;
import com.teaming.cloud.framework2.common.pojo.PageRequest;
import com.teaming.cloud.framework2.common.pojo.PageResult;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 半成品应力信息 服务实现类
 * </p>
 *
 * @author wujie
 * @since 2024-03-11
 */
@Service
public class QualityStressServiceImpl extends ServiceImpl<QualityStressMapper, QualityStress> implements QualityStressService {

    @Autowired
    private FileApi fileApi;

//    @Autowired
//    private RedisSingleService redisService;

    @Autowired
    private RedisSingleService redisService;

    @Autowired
    private SpecsConfigService specsConfigService;

    @Override
    public void saveInfo(QualityStress qualityStress) {
        LocalDateTime now = LocalDateTime.now();
        if (qualityStress.getTransectTime() == null) {
            qualityStress.setTransectTime(now);
        }
        if (qualityStress.getRecordTime() == null) {
            qualityStress.setRecordTime(now);
        }

        this.save(qualityStress);
        //更新文件对应业务Id
        if (CollectionUtils.isNotEmpty(qualityStress.getFileIds())) {
            FileBusiness fileBusiness = new FileBusiness();
            fileBusiness.setFileIds(qualityStress.getFileIds());
            fileBusiness.setBusinessId(qualityStress.getStressId());
            fileApi.updateBusinessById(fileBusiness);
        }
    }

    @Override
    public void updateInfo(QualityStress qualityStress) {
        //更新文件信息
        if (CollectionUtils.isNotEmpty(qualityStress.getDeleteFileIds())) {
            fileApi.deleteByFileIds(qualityStress.getDeleteFileIds());
        }
        //新增文件
        if (CollectionUtils.isNotEmpty(qualityStress.getFileIds())) {
            FileBusiness fileBusiness = new FileBusiness();
            fileBusiness.setBusinessId(qualityStress.getStressId());
            fileBusiness.setFileIds(qualityStress.getFileIds());
            fileApi.updateBusinessById(fileBusiness);
        }

        this.updateById(qualityStress);
    }

    @Override
    public void delete(String id) {
        lambdaUpdate().eq(QualityStress::getStressId, id).set(QualityStress::getIsDelete, CommonConstant.ONE_STR).update();
    }

    @Override
    public PageResult<QualityStress> queryPage(PageRequest<QualityStressReq> pageRequest) {
        final QualityStressReq param = pageRequest.getParam();
        final LambdaQueryWrapper<QualityStress> lambda = new QueryWrapper<QualityStress>().lambda();
        this.buildCondition(lambda, param);
        lambda.orderByDesc(QualityStress::getTransectTime);
        final IPage<QualityStress> page = this.page(new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize()), lambda);
        if (page != null && CollectionUtils.isNotEmpty(page.getRecords())) {
            List<String> ids = page.getRecords().stream().map(c -> c.getStressId()).collect(Collectors.toList());
            ResultBody<List<FileBusiness>> resultBody = fileApi.getFileBusinessByIds(ids);
            Map<String, List<String>> fileMap = null;
            if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
                fileMap = resultBody.getData().stream().collect(Collectors.toMap(f -> f.getBusinessId(), f -> f.getFileIds(), (f1, f2) -> f1));
            }

            List<SpecsConfig> configs = specsConfigService.getSpecsConfigByIds(page.getRecords().stream().map(qt -> qt.getCheckRule()).collect(Collectors.toList()));
            Map<String, SpecsConfig> configMap = null;
            if (CollectionUtils.isNotEmpty(configs)) {
                configMap = configs.stream().collect(Collectors.toMap(c -> c.getSpecsId(), c -> c, (c1, c2) -> c1));
            }

            Map<Object, Object> userMap = redisService.hmget(RedisKey.USER_GROUP_TYPE);

            for (QualityStress record : page.getRecords()) {
                if (fileMap != null) {
                    record.setFileIds(fileMap.get(record.getStressId()));
                }
                if (userMap != null) {
                    record.setUserName(userMap.get(record.getUserId()) == null ? "" : userMap.get(record.getUserId()).toString());
                }
                if (configMap != null) {
                    record.setSpecsConfig(configMap.get(record.getCheckRule()));
                }
            }
        }

        PageResult<QualityStress> pr = new PageResult(page);
        return pr;
    }

    @Override
    public List<QualityStress> queryQualityStress(QualityStressReq stressReq) {
        final LambdaQueryWrapper<QualityStress> lambda = new QueryWrapper<QualityStress>().lambda();
        this.buildCondition(lambda, stressReq);
        lambda.orderByAsc(QualityStress::getTransectTime);
        List<QualityStress> list = this.list(lambda);
        Map<Object, Object> userMap = redisService.hmget(RedisKey.USER_GROUP_TYPE);
        for (QualityStress qs : list) {
            if (userMap != null) {
                qs.setUserName(userMap.get(qs.getUserId()) == null ? "" : userMap.get(qs.getUserId()).toString());
            }
        }
        return list;
    }

    @Override
    public StressExcelDataResp importStress(List<MultipartFile> files) {
        StressExcelDataResp stress = new StressExcelDataResp();
        if (CollectionUtils.isNotEmpty(files)) {
            for (MultipartFile file : files) {
                String fileName = file.getOriginalFilename();
                if (StringUtils.isBlank(fileName)) continue;
                int dotIndex = fileName.lastIndexOf('.');
                String suffix = fileName.substring(dotIndex + 1);
                if (StringUtils.isBlank(suffix)) continue;
                if (Constants.FILE_TYPE_DAT.equals(suffix)) {
                    InputStream inputStream = null;
                    BufferedReader br = null;
                    InputStreamReader isr = null;
                    try {
                        inputStream = file.getInputStream();
                        isr = new InputStreamReader(inputStream);
                        br = new BufferedReader(isr);
                        String line = "";
                        int i = 0;
                        List<Double> ds = new ArrayList();
                        double m = 0;
                        double n = 0;
                        while ((line = br.readLine()) != null) {
                            if (i > 66) {
                                if (StringUtils.isNotBlank(line)) {
                                    String[] datas = line.trim().split("\\s+");
                                    if (StringUtils.isNotBlank(datas[7])) {
                                        double value = Double.valueOf(datas[7]);
                                        if (value <= 120) {
                                            m++;
                                        }
                                        ds.add(value);
                                    }
                                    n++;
                                }
                            }
                            i++;
                        }
                        double percent = m / n;
                        double max = ds.stream().max(Double::compareTo).get();
                        double min = ds.stream().min(Double::compareTo).get();
                        double average = ds.stream().collect(Collectors.averagingDouble(Double::doubleValue));
                        double deviation = SPCUtils.calculateStandardDeviation(ds);
                        DecimalFormat df = new DecimalFormat("#.0000");
                        stress.setStdev(Double.valueOf(df.format(deviation)));
                        stress.setStdev3(Double.valueOf(df.format(deviation * 3)));
                        stress.setAverageValue(Double.valueOf(df.format(average)));
                        stress.setMinValue(Double.valueOf(df.format(min)));
                        stress.setMaxValue(Double.valueOf(df.format(max)));
                        DecimalFormat dfp = new DecimalFormat("#.000");
                        stress.setPercentage(Double.valueOf(dfp.format(percent)) * 100);
                    } catch (Exception ex) {
                        log.error("读取DAT文件异常:" + ex.getMessage());
                    } finally {
                        try {
                            if (inputStream != null) {
                                inputStream.close();
                            }
                            if (br != null) {
                                br.close();
                            }
                            if (isr != null) {
                                isr.close();
                            }
                        } catch (IOException e) {
                            log.error("流关闭异常:" + e.getMessage());
                        }
                    }

                } else if (Constants.FILE_TYPE_XLS.equals(suffix)
                        || Constants.FILE_TYPE_XLSX.equals(suffix)) {
                    InputStream inputStream = null;
                    Workbook workbook = null;
                    try {
                        inputStream = file.getInputStream();
                        workbook = WorkbookFactory.create(inputStream);
                        int sheetCount = workbook.getNumberOfSheets();
                        if (sheetCount == CommonConstant.ONE_INT) {
                            Sheet sheet = workbook.getSheetAt(CommonConstant.ZERO_INT);
                            if (sheet != null) {
                                int rowNum = sheet.getLastRowNum();
                                if (rowNum > 67) {
                                    List<Double> datas = new ArrayList<>();
                                    double m = 0;
                                    double n = 0;
                                    for (int i = 67; i <= rowNum; i++) {
                                        Row row = sheet.getRow(i);
                                        Cell cell = row.getCell(CommonConstant.SEVEN_INT);
                                        double value = cell.getNumericCellValue();
                                        datas.add(value);
                                        if (value < 120) {
                                            m++;
                                        }
                                        n++;
                                    }

                                    double percent = m / n;
                                    double max = datas.stream().max(Double::compareTo).get();
                                    double min = datas.stream().min(Double::compareTo).get();
                                    double average = datas.stream().collect(Collectors.averagingDouble(Double::doubleValue));
                                    double deviation = SPCUtils.calculateStandardDeviation(datas);
                                    DecimalFormat df = new DecimalFormat("#.0000");
                                    stress.setStdev(Double.valueOf(df.format(deviation)));
                                    stress.setStdev3(Double.valueOf(df.format(deviation * 3)));
                                    stress.setAverageValue(Double.valueOf(df.format(average)));
                                    stress.setMinValue(Double.valueOf(df.format(min)));
                                    stress.setMaxValue(Double.valueOf(df.format(max)));
                                    DecimalFormat dfp = new DecimalFormat("#.000");
                                    stress.setPercentage(Double.valueOf(dfp.format(percent)) * 100);
                                }
                            }
                        }

                    } catch (Exception e) {
                        log.error("执行流操作异常:" + e.getMessage());
                        throw new ServiceException(QualityErrorCode.SEMI_IMPORT_FILE_ERROR.getCode(), QualityErrorCode.SEMI_IMPORT_FILE_ERROR.getMsg());
                    } finally {
                        try {
                            if (inputStream != null) {
                                inputStream.close();
                            }
                            if (workbook != null) {
                                workbook.close();
                            }
                        } catch (IOException e) {
                            log.error("流关闭异常:" + e.getMessage());
                        }
                    }
                }

            }

            ResultBody<List<String>> resultBody = fileApi.uploadFiles(files);
            if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
                stress.setFileIds(resultBody.getData());
            }

        }
        return stress;
    }

    @Override
    public List<SemiCheckDetailData> queryStressCheckData(SemiCheckReportReq reportReq) {
        return baseMapper.queryStressCheckData(reportReq);
    }

    /**
     * 构造查询条件
     *
     * @param lambda
     * @param param
     */
    private void buildCondition(LambdaQueryWrapper<QualityStress> lambda, QualityStressReq param) {
        lambda.eq(QualityStress::getIsDelete, CommonConstant.ZERO_STR);
        if (null == param) return;
        if (StringUtils.isNotBlank(param.getStressId())) {
            lambda.eq(QualityStress::getStressId, param.getStressId());
        }
        if (StringUtils.isNotBlank(param.getProductLine())) {
            lambda.eq(QualityStress::getProductLine, param.getProductLine());
        }
        if (StringUtils.isNotBlank(param.getGlassId())) {
            lambda.eq(QualityStress::getGlassId, param.getGlassId());
        }
        if (StringUtils.isNotBlank(param.getGlassType())) {
            lambda.eq(QualityStress::getGlassType, param.getGlassType());
        }
        if (StringUtils.isNotBlank(param.getGlassModel())) {
            lambda.eq(QualityStress::getGlassModel, param.getGlassModel());
        }
        if (StringUtils.isNotBlank(param.getCheckRule())) {
            lambda.eq(QualityStress::getCheckRule, param.getCheckRule());
        }
        if (StringUtils.isNotBlank(param.getDecide())) {
            lambda.eq(QualityStress::getDecide, param.getDecide());
        }
        if (StringUtils.isNotBlank(param.getUserId())) {
            lambda.eq(QualityStress::getUserId, param.getUserId());
        }
        if (param.getRecordStartTime() != null && param.getRecordEndTime() != null) {
            lambda.ge(QualityStress::getRecordTime, param.getRecordStartTime());
            lambda.le(QualityStress::getRecordTime, param.getRecordEndTime());
        }
        if (param.getTransectStartTime() != null && param.getTransectEndTime() != null) {
            lambda.ge(QualityStress::getTransectTime, param.getTransectStartTime());
            lambda.le(QualityStress::getTransectTime, param.getTransectEndTime());
        }
        if (StringUtils.isNotBlank(param.getTeam())) {
            lambda.eq(QualityStress::getTeam, param.getTeam());
        }
        if (StringUtils.isNotBlank(param.getIsRetrospect())) {
            lambda.eq(QualityStress::getIsRetrospect, param.getIsRetrospect());
        }

    }
}
